1   /*
2    * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  
27  package javax.management.openmbean;
28  
29  
30  // java import
31  //
32  import java.io.InvalidObjectException;
33  import java.io.ObjectStreamException;
34  import java.math.BigDecimal;
35  import java.math.BigInteger;
36  import java.util.Date;
37  import java.util.Map;
38  import java.util.HashMap;
39  
40  // jmx import
41  //
42  import javax.management.ObjectName;
43  
44  
45  /**
46   * The <code>SimpleType</code> class is the <i>open type</i> class whose instances describe
47   * all <i>open data</i> values which are neither arrays,
48   * nor {@link CompositeData <code>CompositeData</code>} values,
49   * nor {@link TabularData <code>TabularData</code>} values.
50   * It predefines all its possible instances as static fields, and has no public constructor.
51   * <p>
52   * Given a <code>SimpleType</code> instance describing values whose Java class name is <i>className</i>,
53   * the internal fields corresponding to the name and description of this <code>SimpleType</code> instance
54   * are also set to <i>className</i>.
55   * In other words, its methods <code>getClassName</code>, <code>getTypeName</code> and <code>getDescription</code>
56   * all return the same string value <i>className</i>.
57   *
58   * @since 1.5
59   */
60  public final class SimpleType<T> extends OpenType<T> {
61  
62      /* Serial version */
63      static final long serialVersionUID = 2215577471957694503L;
64  
65      // SimpleType instances.
66      // IF YOU ADD A SimpleType, YOU MUST UPDATE OpenType and typeArray
67  
68      /**
69       * The <code>SimpleType</code> instance describing values whose
70       * Java class name is <code>java.lang.Void</code>.
71       */
72      public static final SimpleType<Void> VOID =
73          new SimpleType<Void>(Void.class);
74  
75      /**
76       * The <code>SimpleType</code> instance describing values whose
77       * Java class name is <code>java.lang.Boolean</code>.
78       */
79      public static final SimpleType<Boolean> BOOLEAN =
80          new SimpleType<Boolean>(Boolean.class);
81  
82      /**
83       * The <code>SimpleType</code> instance describing values whose
84       * Java class name is <code>java.lang.Character</code>.
85       */
86      public static final SimpleType<Character> CHARACTER =
87          new SimpleType<Character>(Character.class);
88  
89      /**
90       * The <code>SimpleType</code> instance describing values whose
91       * Java class name is <code>java.lang.Byte</code>.
92       */
93      public static final SimpleType<Byte> BYTE =
94          new SimpleType<Byte>(Byte.class);
95  
96      /**
97       * The <code>SimpleType</code> instance describing values whose
98       * Java class name is <code>java.lang.Short</code>.
99       */
100     public static final SimpleType<Short> SHORT =
101         new SimpleType<Short>(Short.class);
102 
103     /**
104      * The <code>SimpleType</code> instance describing values whose
105      * Java class name is <code>java.lang.Integer</code>.
106      */
107     public static final SimpleType<Integer> INTEGER =
108         new SimpleType<Integer>(Integer.class);
109 
110     /**
111      * The <code>SimpleType</code> instance describing values whose
112      * Java class name is <code>java.lang.Long</code>.
113      */
114     public static final SimpleType<Long> LONG =
115         new SimpleType<Long>(Long.class);
116 
117     /**
118      * The <code>SimpleType</code> instance describing values whose
119      * Java class name is <code>java.lang.Float</code>.
120      */
121     public static final SimpleType<Float> FLOAT =
122         new SimpleType<Float>(Float.class);
123 
124     /**
125      * The <code>SimpleType</code> instance describing values whose
126      * Java class name is <code>java.lang.Double</code>.
127      */
128     public static final SimpleType<Double> DOUBLE =
129         new SimpleType<Double>(Double.class);
130 
131     /**
132      * The <code>SimpleType</code> instance describing values whose
133      * Java class name is <code>java.lang.String</code>.
134      */
135     public static final SimpleType<String> STRING =
136         new SimpleType<String>(String.class);
137 
138     /**
139      * The <code>SimpleType</code> instance describing values whose
140      * Java class name is <code>java.math.BigDecimal</code>.
141      */
142     public static final SimpleType<BigDecimal> BIGDECIMAL =
143         new SimpleType<BigDecimal>(BigDecimal.class);
144 
145     /**
146      * The <code>SimpleType</code> instance describing values whose
147      * Java class name is <code>java.math.BigInteger</code>.
148      */
149     public static final SimpleType<BigInteger> BIGINTEGER =
150         new SimpleType<BigInteger>(BigInteger.class);
151 
152     /**
153      * The <code>SimpleType</code> instance describing values whose
154      * Java class name is <code>java.util.Date</code>.
155      */
156     public static final SimpleType<Date> DATE =
157         new SimpleType<Date>(Date.class);
158 
159     /**
160      * The <code>SimpleType</code> instance describing values whose
161      * Java class name is <code>javax.management.ObjectName</code>.
162      */
163     public static final SimpleType<ObjectName> OBJECTNAME =
164         new SimpleType<ObjectName>(ObjectName.class);
165 
166     private static final SimpleType<?>[] typeArray = {
167         VOID, BOOLEAN, CHARACTER, BYTE, SHORT, INTEGER, LONG, FLOAT,
168         DOUBLE, STRING, BIGDECIMAL, BIGINTEGER, DATE, OBJECTNAME,
169     };
170 
171 
172     private transient Integer myHashCode = null;        // As this instance is immutable, these two values
173     private transient String  myToString = null;        // need only be calculated once.
174 
175 
176     /* *** Constructor *** */
177 
178     private SimpleType(Class<T> valueClass) {
179         super(valueClass.getName(), valueClass.getName(), valueClass.getName(),
180               false);
181     }
182 
183 
184     /* *** SimpleType specific information methods *** */
185 
186     /**
187      * Tests whether <var>obj</var> is a value for this
188      * <code>SimpleType</code> instance.  <p> This method returns
189      * <code>true</code> if and only if <var>obj</var> is not null and
190      * <var>obj</var>'s class name is the same as the className field
191      * defined for this <code>SimpleType</code> instance (ie the class
192      * name returned by the {@link OpenType#getClassName()
193      * getClassName} method).
194      *
195      * @param obj the object to be tested.
196      *
197      * @return <code>true</code> if <var>obj</var> is a value for this
198      * <code>SimpleType</code> instance.
199      */
200     public boolean isValue(Object obj) {
201 
202         // if obj is null, return false
203         //
204         if (obj == null) {
205             return false;
206         }
207 
208         // Test if obj's class name is the same as for this instance
209         //
210         return this.getClassName().equals(obj.getClass().getName());
211     }
212 
213 
214     /* *** Methods overriden from class Object *** */
215 
216     /**
217      * Compares the specified <code>obj</code> parameter with this <code>SimpleType</code> instance for equality.
218      * <p>
219      * Two <code>SimpleType</code> instances are equal if and only if their
220      * {@link OpenType#getClassName() getClassName} methods return the same value.
221      *
222      * @param  obj  the object to be compared for equality with this <code>SimpleType</code> instance;
223      *              if <var>obj</var> is <code>null</code> or is not an instance of the class <code>SimpleType</code>,
224      *              <code>equals</code> returns <code>false</code>.
225      *
226      * @return  <code>true</code> if the specified object is equal to this <code>SimpleType</code> instance.
227      */
228     public boolean equals(Object obj) {
229 
230         /* If it weren't for readReplace(), we could replace this method
231            with just:
232            return (this == obj);
233         */
234 
235         if (!(obj instanceof SimpleType<?>))
236             return false;
237 
238         SimpleType<?> other = (SimpleType<?>) obj;
239 
240         // Test if other's className field is the same as for this instance
241         //
242         return this.getClassName().equals(other.getClassName());
243     }
244 
245     /**
246      * Returns the hash code value for this <code>SimpleType</code> instance.
247      * The hash code of a <code>SimpleType</code> instance is the the hash code of
248      * the string value returned by the {@link OpenType#getClassName() getClassName} method.
249      * <p>
250      * As <code>SimpleType</code> instances are immutable, the hash code for this instance is calculated once,
251      * on the first call to <code>hashCode</code>, and then the same value is returned for subsequent calls.
252      *
253      * @return  the hash code value for this <code>SimpleType</code> instance
254      */
255     public int hashCode() {
256 
257         // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode())
258         //
259         if (myHashCode == null) {
260             myHashCode = Integer.valueOf(this.getClassName().hashCode());
261         }
262 
263         // return always the same hash code for this instance (immutable)
264         //
265         return myHashCode.intValue();
266     }
267 
268     /**
269      * Returns a string representation of this <code>SimpleType</code> instance.
270      * <p>
271      * The string representation consists of
272      * the name of this class (ie <code>javax.management.openmbean.SimpleType</code>) and the type name
273      * for this instance (which is the java class name of the values this <code>SimpleType</code> instance represents).
274      * <p>
275      * As <code>SimpleType</code> instances are immutable, the string representation for this instance is calculated once,
276      * on the first call to <code>toString</code>, and then the same value is returned for subsequent calls.
277      *
278      * @return  a string representation of this <code>SimpleType</code> instance
279      */
280     public String toString() {
281 
282         // Calculate the string representation if it has not yet been done (ie 1st call to toString())
283         //
284         if (myToString == null) {
285             myToString = this.getClass().getName()+ "(name="+ getTypeName() +")";
286         }
287 
288         // return always the same string representation for this instance (immutable)
289         //
290         return myToString;
291     }
292 
293     private static final Map<SimpleType<?>,SimpleType<?>> canonicalTypes =
294         new HashMap<SimpleType<?>,SimpleType<?>>();
295     static {
296         for (int i = 0; i < typeArray.length; i++) {
297             final SimpleType<?> type = typeArray[i];
298             canonicalTypes.put(type, type);
299         }
300     }
301 
302     /**
303      * Replace an object read from an {@link
304      * java.io.ObjectInputStream} with the unique instance for that
305      * value.
306      *
307      * @return the replacement object.
308      *
309      * @exception ObjectStreamException if the read object cannot be
310      * resolved.
311      */
312     public Object readResolve() throws ObjectStreamException {
313         final SimpleType<?> canonical = canonicalTypes.get(this);
314         if (canonical == null) {
315             // Should not happen
316             throw new InvalidObjectException("Invalid SimpleType: " + this);
317         }
318         return canonical;
319     }
320 }